﻿using RockBus.Configuration;
using RockBus.DataContracts;
using RockBus.Logging.Interfaces;
using System;
using System.Linq;
using System.Configuration;
using System.Threading.Tasks;

namespace RockBus.ServiceBus
{
    public class SubscriberClient
    {
        /// <summary>
        /// Creates a SubscriberClient using the specified client and subscriber configuration (configuration the application configuration file is ignored).
        ///  The provided Message Types are scanned for the RockBusAttribute attribute.
        /// </summary>
        /// <param name="messageHandler">The instance of the ITypedMessageHandler or IMessageHandler that will handle the messages.</param>
        /// <param name="subscriberInfo">Contains the subscription information, to which this SubscriberClient will subscribe.</param>
        /// <param name="rockBusEndpoint">Contains the endpoint information used to connect with RockBus.</param>
        public SubscriberClient(ILogger logger, IMessageHandler messageHandler, SubscriberInfo subscriberInfo = null, EndpointInfo rockBusEndpoint = null)
        {
            this.ServiceBusEnvironment = new ServiceBusEnvironment(logger, rockBusEndpoint);
            this.MessageHandler = messageHandler;

            if (subscriberInfo == null)
            {
                if ((null == ServiceBusClientConfigurationSection.Instance) || (null == ServiceBusClientConfigurationSection.Instance.Subscribers))
                {
                    throw new ConfigurationErrorsException("The ServiceBus Subscriber(s) were not configured. Pls. refer to RockBus.Configuration.ServiceBusClientConfigurationSection for the configuration schemas and documentation.");
                }

                var sc = ServiceBusClientConfigurationSection.Instance.Subscribers.CreateSubscriberConfiguration(false);
                subscriberInfo = sc.EvaluationElementDictionary[messageHandler.Id];
            }

            this.SubscriberInfo = subscriberInfo;
            if (subscriberInfo.EndpointInfoDictionary.Count > 1)
            {
                throw new ConfigurationErrorsException("For the moment, only 1 endpoint is supported.");
            }
        }

        public ILogger Logger { get; private set; }

        private ServiceBusEnvironment ServiceBusEnvironment { get; set; }

        private SubscriberInfo SubscriberInfo { get; set; }

        private IMessageHandler MessageHandler { get; set; }

        #region Subscribers

        /// <summary>
        /// Subscribes to the subscriptions for the SubscriberInfo.
        /// </summary>
        /// <returns></returns>
        public async Task SubscribeAsync(bool openServiceHost = true)
        {
            if (openServiceHost)
            {
                var opened = await this.ServiceBusEnvironment.TryCreateAndOpenServiceHostAsync(this.MessageHandler, this.SubscriberInfo.EndpointInfoDictionary.Values.First());
            }

            var sc = new SubscriberConfiguration(this.SubscriberInfo);
            var request = new AddOrUpdateSubscribersRequest(sc);
            await this.ServiceBusEnvironment.AddOrUpdateSubscribersAsync(request);
        }

        /// <summary>
        /// Removes all subscriptions for the SubscriberInfo.
        /// </summary>
        /// <returns></returns>
        public async Task UnsubscribeAsync()
        {
            await this.ServiceBusEnvironment.TryCloseServiceHost(this.MessageHandler.Id);

            var request = new RemoveSubscribersRequest(this.MessageHandler.Id);
            await this.ServiceBusEnvironment.RemoveSubscribersAsync(request);
        }

        #endregion Subscribers
    }
}